package com.kintreda.common.oauth.security.config;


import com.kintreda.common.config.security.SecurityRequestConfig;
import com.kintreda.common.oauth.security.AuthAccessDecisionManager;
import com.kintreda.common.oauth.security.AuthFilterInvocationSecurityMetadataSource;
import com.kintreda.common.oauth.security.filter.BaseJwtAuthenticationTokenFilter;
import com.kintreda.common.oauth.security.handler.BaseAuthenticationEntryPoint;
import com.kintreda.common.oauth.security.handler.BaseRestAccessDeniedHandler;
import com.kintreda.common.oauth.security.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.util.List;


/**
 * Created with IntelliJ IDEA.
 * Date: 2020/1/2
 * Time: 7:55 下午
 * Description: WebSecurity核心配置
 * The following English comments (including this sentence are translated using plugins, so ...)
 * You can use the translation plugin that comes with idea .....
 */
@Slf4j
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    @Resource
    UserService userService;

    /**
     * 未携带token用户, 或者非法token访问无权限资源时的异常
     */
    @Resource
    BaseAuthenticationEntryPoint baseAuthenticationEntryPoint;

    /**
     * 没有权限,被拒绝访问时的调用类
     */
    @Resource
    BaseRestAccessDeniedHandler baseRestAccessDeniedHandler;

    /**
     * 权限拦截器
     */
    @Resource
    private AuthFilterInvocationSecurityMetadataSource authFilterInvocationSecurityMetadataSource;

    /**
     * 权限决策器
     */
    @Resource
    private AuthAccessDecisionManager authAccessDecisionManager;

    /**
     * initialize the secure request collection
     */
    protected List<String> securityRequestList = new SecurityRequestConfig().securityRequestList;



    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 放行策略
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        securityRequestList.forEach(x->{
            web.ignoring().antMatchers(x);
            log.info("放行接口->>  {}", x);
        });
    }



    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setSecurityMetadataSource(authFilterInvocationSecurityMetadataSource);
                        o.setAccessDecisionManager(authAccessDecisionManager);
                        return o;
                    }
                })

                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                .csrf().disable().authorizeRequests().anyRequest().authenticated()

                .and()
                .exceptionHandling()
                .accessDeniedHandler(baseRestAccessDeniedHandler)
                .authenticationEntryPoint(baseAuthenticationEntryPoint)

                .and()
                .addFilterBefore(new BaseJwtAuthenticationTokenFilter(userService), UsernamePasswordAuthenticationFilter.class);



    }





}
